﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Djs.Tools.XmlPersistor
{
    #region class Persist : Třída, která zajišťuje persistenci dat do / z XML formátu
    /// <summary>
    /// Třída, která zajišťuje persistenci dat do / z XML formátu
    /// </summary>
    public static class Persist
    {
        #region Statické public metody
        /// <summary>
        /// Zajistí persistenci (uložení = serializaci) datového objektu do stringu podle implicitních parametrů.
		/// Vrátí stringovou reprezentaci objektu.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Serialize(object data)
        {
            return Serialize(data, PersistArgs.Default);
        }
        /// <summary>
        /// Zajistí persistenci (uložení = serializaci) datového objektu do stringu podle daných parametrů.
		/// Pokud je v parametru vyplněn soubor (XmlFile), pak je XML uložen do daného souboru, v korektním kódování UTF-8 (včetně záhlaví XML!)
		/// Vrátí stringovou reprezentaci objektu.
		/// </summary>
        /// <param name="data"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static string Serialize(object data, PersistArgs parameters)
        {
            return XmlPersist.Serialize(data, parameters);
        }
        /// <summary>
        /// Vytvoří objekt ze serializovaného stavu, který je dodán jako string do této metody.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static object Deserialize(string source)
        {
            return Deserialize(CreateArgs(source));
        }
        /// <summary>
		/// Vytvoří objekt ze serializovaného stavu, který je definován v argumentu (může to být string, nebo soubor).
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object Deserialize(PersistArgs parameters)
        {
            return XmlPersist.Deserialize(parameters);
        }
        /// <summary>
        /// Určená data rekonstruuje a naplní je do předaného objektu.
        /// Pokud objekt je null, vytvoří jej.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="data"></param>
        public static void LoadTo(string source, object data)
        {
            LoadTo(CreateArgs(source), data);
        }
        /// <summary>
        /// Určená data rekonstruuje a naplní je do předaného objektu.
        /// Předaný objekt nemůže být null, protože se nepředává jako reference (ref).
		/// Pokud by měl být objekt null, je třeba využít metodu Persist.Deserialize().
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="data"></param>
        public static void LoadTo(PersistArgs parameters, object data)
        {
            XmlPersist.LoadTo(parameters, data);
        }
        /// <summary>
        /// Hodnoty ze vstupního objektu přenese do cílového objektu.
        /// Používá XML persistenci, takže přenáší jen ty hodnoty, které jsou serializovatelné.
        /// Provádí tedy hluboké klonování.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        public static void CloneTo(object source, object target)
        {
            if (source == null || target == null) return;

            PersistArgs args = PersistArgs.MinimalXml;
            string xmlSource = XmlPersist.Serialize(source, args);
            LoadTo(xmlSource, target);
        }
        /// <summary>
        /// Vrátí defaultní parametry, do nichž naplní source do XmlContent nebo do XmlFile
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private static PersistArgs CreateArgs(string source)
        {
            if (source == null) return null;
            PersistArgs parameters = PersistArgs.Default;
            if (source.Trim().StartsWith("<"))
                parameters.XmlContent = source;
            else
                parameters.XmlFile = source;
            return parameters;
        }
        #endregion
    }
    #endregion
    #region class PersistArgs : parametry pro persistenci objektu
    /// <summary>
    /// class PersistArgs : parametry pro persistenci objektu
    /// </summary>
    public class PersistArgs
    {
        public PersistArgs()
        {
            XmlWriterSettings xs = new XmlWriterSettings();
            xs.ConformanceLevel = ConformanceLevel.Document;
            xs.Encoding = Encoding.UTF8;
            xs.CheckCharacters = false;
            xs.Indent = true;
            xs.IndentChars = "  ";
            xs.NewLineHandling = NewLineHandling.Entitize;
            xs.NewLineChars = Environment.NewLine;
            xs.NewLineOnAttributes = false;
            xs.OmitXmlDeclaration = false;
            this.WriterSettings = xs;
        }
        /// <summary>
        /// Defaultní parametry
        /// </summary>
        public static PersistArgs Default
        {
            get { return new PersistArgs(); }
        }
        /// <summary>
        /// Parametry pro vytváření minimálního XML textu
        /// </summary>
        public static PersistArgs MinimalXml
        {
            get
            {
                PersistArgs args = new PersistArgs();
                args.WriterSettings.ConformanceLevel = ConformanceLevel.Document;
                args.WriterSettings.Encoding = Encoding.UTF8;
                args.WriterSettings.CheckCharacters = false;
                args.WriterSettings.Indent = false;
                args.WriterSettings.IndentChars = "";
                args.WriterSettings.NewLineHandling = NewLineHandling.None;
                args.WriterSettings.NewLineChars = Environment.NewLine;
                args.WriterSettings.NewLineOnAttributes = false;
                args.WriterSettings.OmitXmlDeclaration = false;
                return args;
            }
        }
        /// <summary>
        /// Nastavení pro zápis XML
        /// </summary>
        public XmlWriterSettings WriterSettings { get; set; }
        /// <summary>
        /// Soubor pro načtení/uložení XML. Pokud bude null, nebude se načítat/ukládat ze souboru, ale použije se string XmlContent.
        /// </summary>
        public string XmlFile { get; set; }
        /// <summary>
        /// Obsah XML dat.
        /// Při načítání (Load), pokud je určen soubor XmlFile, je obsah uložen sem (obsah souboru se načte a vloží do XmlContent). 
        /// Pokud při Load není soubor XmlFile určen, přebírá se XML text odsud.
        /// Při ukládání (Save) je obsah XML vždy uložen i sem.
        /// </summary>
        public string XmlContent { get; set; }
        /// <summary>
        /// Stav deserializace = obsahuje případné problémy
        /// </summary>
        public XmlDeserializeStatus DeserializeStatus { get; set; }
    }
    public enum XmlDeserializeStatus
    {
        None,
        Processing,
        NotInput,
        BadFormatPersistent,
        BadFormatData,
        BadFormatValue
    }
    #endregion
}
